#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU Lesser General Public License.
/// </copyright>
#pragma endregion

#pragma once
#include "_ISourceEvents_CP.H"

class OSHBitmap;

class ATL_NO_VTABLE OSHSource : 
	public CComObjectRootEx<CComMultiThreadModel>,
	public CComCoClass<OSHSource, &__uuidof(OSHLibrary::Source)>,
	public IDispatchImpl<OSHLibrary::ISource, &__uuidof(OSHLibrary::ISource), &__uuidof(OSHLibrary::__OSH), /*wMajor =*/ -1, /*wMinor =*/ -1>,
	public IProvideClassInfo2Impl<&__uuidof(OSHLibrary::Source), NULL, &__uuidof(OSHLibrary::__OSH), -1, -1>,
	public IConnectionPointContainerImpl<OSHSource>,
	public CProxy_ISourceEvents<OSHSource>
{
private:
	enum {
		StopMonitoringTimeout = 1000, // Time in ms
	};

	static const wchar_t* BitmapNumberVariableName;
	static const wchar_t* BitmapSizeVariableName;
	static const wchar_t* BitmapBufferVariableFormat;
	static const wchar_t* BitmapRefCountVariableFormat;
	static const wchar_t* BitmapTimeVariableFormat;
	static const int InvalidRefCountValue = -1;
	static const DWORD InvalidBitmapNumber = 0;

	SharedMemory::CSharedMemory* _sharedMemory;
	bool _isOwner;
	int _maxNumberOfBitmaps;
	DWORD _firstBitmapNumber;
	DWORD _lastActiveBitmapNumber;
	bool _visible;
	ATL::CEvent _closeEvent;
	ATL::CEvent _monitorThreadStopEvent;
	ATL::CHandle _monitorThread;
	ATL::CCriticalSection _eventFireSection;
	bool _saveOnBitmapClose;

	HRESULT StartMonitoring();
	HRESULT StopMonitoring();
	static DWORD WINAPI MonitorThreadProc(OSHSource* self);

	bool IsOpened();
	HRESULT Close(bool destruction);
	HRESULT OpenSharedMemory(const wchar_t* name);
	HRESULT CloseSharedMemory();

	HRESULT ActivateBitmaps();
	HRESULT DeactivateBitmaps();
	HRESULT EnsureBitmapSize(CSize bitmapSize);
	HRESULT AllocateBitmapVariables(CSize bitmapSize, int numberOfBitmaps, DWORD firstBitmapNumber);
	HRESULT FreeBitmapVariables(int numberOfBitmaps, DWORD firstBitmapNumber);
	HRESULT ActivateBitmapSlot(DWORD bitmapNumber);
	HRESULT ActivateInvalidBitmapSlot(DWORD& lastActiveBitmapNumber);
	HRESULT GetLastUsedBitmapSlot(DWORD* bitmapNumber, BITMAPINFOHEADER** bitmapHeader, void** bitmapData);
	HRESULT CheckBitmapSize(int width, int height);

public:
	void FireOnShow();
	void FireOnHide();
	void FireOnRefresh();

public:
	OSHSource();
	virtual ~OSHSource();

	DECLARE_REGISTRY_RESOURCEID(IDR_OSHSOURCE)

	BEGIN_COM_MAP(OSHSource)
		COM_INTERFACE_ENTRY(OSHLibrary::ISource)
		COM_INTERFACE_ENTRY(IDispatch)
		COM_INTERFACE_ENTRY(IConnectionPointContainer)
		COM_INTERFACE_ENTRY(IProvideClassInfo)
		COM_INTERFACE_ENTRY(IProvideClassInfo2)
	END_COM_MAP()

	BEGIN_CONNECTION_POINT_MAP(OSHSource)
		CONNECTION_POINT_ENTRY(__uuidof(OSHLibrary::_ISourceEvents))
	END_CONNECTION_POINT_MAP()

	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}
	
	void FinalRelease() 
	{
	}

public:

	HRESULT OnBitmapClose(OSHBitmap& bitmap);

	// ISource Members
	STDMETHOD(get_State)(OSHLibrary::StateEnum* state);
	STDMETHOD(get_Visible)(VARIANT_BOOL* pVal);
	STDMETHOD(put_Visible)(VARIANT_BOOL newVal);

	STDMETHOD(Create)(BSTR name, int maxNumberOfBitmaps, int maxBitmapWidth, int maxBitmapHeight);
	STDMETHOD(Open)(VARIANT name);
	STDMETHOD(Close)();

	//STDMETHOD(SetBitmapSize)(int width, int height);

	STDMETHOD(GetVisibleBitmap)(OSHLibrary::IBitmap** ppBitmap);
	STDMETHOD(WaitForBitmap)(LONG dwMilliseconds, OSHLibrary::IBitmap** ppBitmap);
	STDMETHOD(WaitForBitmapEx)(LONG dwMilliseconds, int cancelHandle, OSHLibrary::IBitmap** ppBitmap);

	STDMETHOD(CreateBitmap)(int width, int height, OSHLibrary::IBitmap** ppBitmap);
	STDMETHOD(ShowAndCloseBitmap)(OSHLibrary::IBitmap* ppBitmap);
};

OBJECT_ENTRY_AUTO(__uuidof(OSHLibrary::Source), OSHSource)
